package top.v5it.japi.ddd.core.web;

import cn.hutool.extra.servlet.ServletUtil;
import org.springframework.web.bind.annotation.*;
import top.v5it.japi.ddd.core.entity.Entity;
import top.v5it.japi.ddd.core.util.EntityUtils;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author zhanpu
 * @date 2023/3/13
 */
@RestController
public class BatchController extends BaseController {

    @RequestMapping(value = "batch/{bean}/{method}", method = {RequestMethod.GET, RequestMethod.POST})
    public Object batch(@PathVariable("bean") String bean, @PathVariable("method") String methodName,
                        @RequestBody List<HashMap<String, Object>> jsons, HttpServletRequest request) {
        HttpHeadFactory.INSTANCE.putRequestHeadAll(ServletUtil.getHeaderMap(request));
        Object service = getBean(bean);
        Method method = getMethod(service, methodName);
        Map<String, Object> json = toMap(null, request);
        Object vo = getValueObj(method, jsons);
        Object[] args = getArguments(method, json, vo);
        return invoke(service, method, args);
    }

    /**
     * get the first parameter of the method, as the value object, and instance, set values from the json.
     * if the json is null or empty, means no value object, then return null.
     * if there is no parameters of the method, then return null.
     *
     * @param method
     * @param jsons
     * @return the value object with it's data.
     */
    @SuppressWarnings({"unchecked", "rawtypes"})
    private Object getValueObj(Method method, List<HashMap<String, Object>> jsons) {
        if (jsons == null || jsons.isEmpty()) return null;
        Class<?>[] allOfParameterTypes = method.getParameterTypes();
        if (allOfParameterTypes.length == 0) return null;
        Class<?> firstOfParameterType = allOfParameterTypes[0];

        if (Iterable.class.isAssignableFrom(firstOfParameterType)) {
            final Type[] genericParameterTypes = method.getGenericParameterTypes();
            final ParameterizedType parameterizedType = (ParameterizedType) genericParameterTypes[0];
            final Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
            final Class<?> clazz = (Class<?>) actualTypeArguments[0];

            if (Map.class.isAssignableFrom(clazz)) return jsons;
            if (!EntityUtils.isEntity(clazz)) return null;
            List<Entity> entities = new ArrayList<>();

            for (Map<String, Object> json : jsons) {
                Entity entity = EntityUtils.createEntity((Class<Entity>) clazz, json);
                validateEntity(entity);
                entities.add(entity);
            }
            return entities;
        }
        throw new IllegalArgumentException(method.getName() + "方法，参数不符");
    }

}
